﻿/*
 * ========================================================================
 * Copyright(c) 2008-2010北京高阳金信信息技术有限公司, All Rights Reserved.
 * ========================================================================
 *  JSON 操作客户端，可用于请求远程WCF，并以Json格式交互数据
 * 
 * 作者：邓太华     时间：2010-06-04至08
 * 版本：V1.0
 * 
 * 修改者：         时间：                
 * 修改说明：
 * ========================================================================
*/

using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
using System.Runtime.Serialization.Json;

namespace Hisuntech.SystemFramework.Net.Json
{
    /// <summary>
    /// JSON 操作客户端，可用于请求远程WCF，并以Json格式交互数据
    /// </summary>
    public static class JSONClient
    {
        /// <summary>
        /// 以GET方式请求WCF服务，并将结果处理成指定的类型。服务端采用JSON格式处理请求和返回值。
        /// </summary>
        /// <param name="url">服务地址，例如请求一个带参数的方法 http://localhost:9162/Service1.svc/GetData?value=10 </param>
        /// <returns>结果字符串</returns>
        /// <example>
        /// 请在WCF的服务方法中，定义 WebMessageBodyStyle.WrappedRequest，便于结果处理。如果结果是复杂的JSON对象，请使用 WebMessageBodyStyle.Wrapped，
        /// 并且使用GetData 方法的重载。
        /// 
        /// [WebGet(BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json)]
        /// public string GetData(int value)
        /// {
        ///     return string.Format("You entered: {0}", value);
        /// }
        /// </example>
        public static string GetResultString(string url)
        {
            var request = GetRequest(url, "GET");
            var stream = request.GetResponse().GetResponseStream();
            using (System.IO.StreamReader reader = new System.IO.StreamReader(stream))
            {
                return reader.ReadToEnd();
            }
        }

        /// <summary>
        /// 以GET方式请求WCF服务，并将结果处理成指定的类型。服务端采用JSON格式处理请求和返回值。
        /// </summary>
        /// <typeparam name="TResult">结果类型</typeparam>
        /// <param name="url">服务地址，例如请求一个带参数的方法 http://localhost:9162/Service1.svc/GetData?value=10 </param>
        /// <returns>返回 TResult 类型的数据</returns>
        public static TResult GetData<TResult>(string url) where TResult : class
        {
            var request = GetRequest(url, "GET");
            var stream = request.GetResponse().GetResponseStream();
            //var streamReader = new System.IO.StreamReader(stream);
            //string ccc = streamReader.ReadToEnd();
            DateTime dt = DateTime.Now;
            var serializer = new DataContractJsonSerializer(typeof(TResult));
            var result = (TResult)serializer.ReadObject(stream);
            System.Diagnostics.Debug.WriteLine("DataContractJsonSerializer use time(ms):" + DateTime.Now.Subtract(dt).TotalMilliseconds);
            return result;
        }

        /// <summary>
        /// 向WCF服务提交数据，服务端采用JSON格式处理请求。如果需要处理返回值，请使用该方法的重载。
        /// </summary>
        /// <typeparam name="TPostData">要提交的数据类型</typeparam>
        /// <param name="url">请求的服务地址，例如 http://localhost:9162/Service1.svc/DataContractList</param>
        /// <param name="data">提交的数据</param>
        public static void PostData<TPostData>(string url, TPostData data) where TPostData : class
        {
            var streamReader = new System.IO.StreamReader(new System.IO.MemoryStream());

            var serializer = new DataContractJsonSerializer(typeof(TPostData));
            serializer.WriteObject(streamReader.BaseStream, data);
            streamReader.BaseStream.Position = 0;

            var request = GetRequest(url, "POST");
            request.ContentType = "application/json; charset=utf-8";
            var bytes = System.Text.Encoding.UTF8.GetBytes(streamReader.ReadToEnd());
            request.ContentLength = bytes.Length;
            var stream = request.GetRequestStream();
            stream.Write(bytes, 0, bytes.Length);
            var r = request.GetResponse();
            r.Close();
            stream.Close();
        }

        /// <summary>
        /// 将一个对象转换成JSON字符串
        /// </summary>
        /// <typeparam name="TPara">对象类型</typeparam>
        /// <param name="data">对象实例</param>
        /// <returns>字符串</returns>
        public static string GetJSONString<TPara>(TPara data) where TPara : class
        {
            return GetJSONString(data, typeof(TPara));
        }

        /// <summary>
        /// 将目标数据安装指定类型进行JSON格式序列化
        /// </summary>
        /// <param name="data"></param>
        /// <param name="targetType"></param>
        /// <returns></returns>
        public static string GetJSONString(object data, Type targetType)
        {
            var streamReader = new System.IO.StreamReader(new System.IO.MemoryStream(), Encoding.UTF8);
            var serializer = new DataContractJsonSerializer(targetType);
            serializer.WriteObject(streamReader.BaseStream, data);
            streamReader.BaseStream.Position = 0;
            var bytes = System.Text.Encoding.UTF8.GetBytes(streamReader.ReadToEnd());
            string result = Encoding.UTF8.GetString(bytes);
            //string result = streamReader.ReadToEnd();
            streamReader.Close();
            return result;
        }

        /// <summary>
        /// 将JSON字符串转换成指定的对象
        /// </summary>
        /// <typeparam name="TResult">结果类型</typeparam>
        /// <param name="json">JSON字符串</param>
        /// <returns>指定的对象</returns>
        public static TResult GetObjectFromJsonString<TResult>(string json)
        {
            //using (System.IO.Stream stream = new System.IO.MemoryStream(Encoding.UTF8.GetBytes(json)))
            //{
            //    var desSerializer = new DataContractJsonSerializer(typeof(TResult));
            //    var result = (TResult)desSerializer.ReadObject(stream);
            //    return result;
            //}
            return (TResult)GetObjectFromJsonString(json, typeof(TResult));
        }

        /// <summary>
        /// 将JSON字符串转换成指定的对象
        /// </summary>
        /// <param name="json"></param>
        /// <param name="t"></param>
        /// <returns></returns>
        public static object GetObjectFromJsonString(string json, Type t)
        {

            byte[] sourcebytes = System.Text.Encoding.Default.GetBytes(json);
            byte[] targetbytes = System.Text.Encoding.Convert(Encoding.Default, Encoding.UTF8, sourcebytes);
            using (System.IO.Stream stream = new System.IO.MemoryStream(targetbytes))//Encoding.UTF8.GetBytes(json)
            {
                var desSerializer = new DataContractJsonSerializer(t);
                var result = desSerializer.ReadObject(stream);
                return result;
            }
        }

        /// <summary>
        /// 向WCF服务提交数据，获取返回的数据，并将返回的数据转换成指定的类型。服务端采用JSON格式处理请求和发送结果。
        /// </summary>
        /// <typeparam name="TPostData">要提交的数据类型</typeparam>
        /// <typeparam name="TResult">返回的数据类型</typeparam>
        /// <param name="url">请求的服务地址，例如 http://localhost:9162/Service1.svc/DataContractList</param>
        /// <param name="data">提交的数据</param>
        /// <returns>返回指定类型的数据</returns>
        /// <example>
        ///  ========================假设服务器上有下面的服务：==================================================
        ///  [ServiceContract]
        /// public interface IService1
        /// {
        ///    [OperationContract]
        ///    string GetData(int value);
        ///    [OperationContract]
        ///    CompositeType GetDataUsingDataContract(CompositeType composite);
        ///    // 任务: 在此处添加服务操作
        ///   [OperationContract(Name = "DataContractList")]
        ///    List<CompositeType> GetDataUsingDataContract(CompositeType ct1, CompositeType ct2);
        /// }
        /// 
        ///  [DataContract]
        ///  public class CompositeType
        ///  {
        ///      bool boolValue = true;
        ///      string stringValue = "Hello ";
        ///      [DataMember]
        ///      public bool BoolValue
        ///      {
        ///          get { return boolValue; }
        ///          set { boolValue = value; }
        ///      }
        ///  
        ///      [DataMember]
        ///      public string StringValue
        ///      {
        ///          get { return stringValue; }
        ///          set { stringValue = value; }
        ///      }
        ///  }
        /// 
        /// [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
        /// public class Service1 : IService1
        /// {
        ///     //注意这里 必须设置 WebMessageBodyStyle.WrappedRequest，客户端才可以正确的解析返回值。        
        ///     [WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, Method = "POST")]
        ///     public List<CompositeType> GetDataUsingDataContract(CompositeType ct1, CompositeType ct2)
        ///     {
        ///         if (ct1 != null && ct2 != null)
        ///         {
        ///             List<CompositeType> list = new List<CompositeType>();
        ///             list.Add(ct1);
        ///             list.Add(ct2);
        ///             return list;
        ///         }
        ///         return null;
        ///     }
        /// }
        /// 
        /// ====================在客户端，可以如下调用该服务===============================
        /// 
        /// 1，先定义封装调用参数的类：
        /// [System.Runtime.Serialization.DataContract(Namespace = "http://schemas.datacontract.org/2004/07/")]
        /// [System.SerializableAttribute()]
        /// public class GetCompositeType
        /// {
        ///     [System.Runtime.Serialization.DataMember(Name = "ct1")]
        ///     public WCFService.CompositeType CT1 { get; set; }
        /// 
        ///     [System.Runtime.Serialization.DataMember(Name = "ct2")]
        ///     public WCFService.CompositeType CT2 { get; set; }
        /// 
        ///     public GetCompositeType(WCFService.CompositeType ct1, WCFService.CompositeType ct2)
        ///     {
        ///         this.CT1 = ct1;
        ///         this.CT2 = ct2;
        ///     }
        /// 
        /// }
        /// 
        /// 也可以这样简单的定义：
        /// [System.SerializableAttribute()]
        /// public class GetCompositeType
        /// {
        ///      public WCFService.CompositeType ct1;//字段名称必须跟请求的方法参数名称一样。
        ///      public WCFService.CompositeType ct2;
        /// 
        /// }
        /// 
        /// 2，接着可以如下调用服务端的方法
        ///  WCFService.CompositeType ct1 = new WCFService.CompositeType();
        /// ct1.BoolValue = true;
        /// ct1.StringValue = "AAA";
        /// WCFService.CompositeType ct2 = new WCFService.CompositeType();
        /// ct2.BoolValue = false ;
        /// ct2.StringValue = "BBB";
        /// 
        /// GetCompositeType getct = new GetCompositeType(ct1, ct2);
        ///
        /// List<WCFService.CompositeType> list = JSONClient.PostData<GetCompositeType, List<WCFService.CompositeType>>("http://localhost:9162/Service1.svc/DataContractList", getct);
        /// 
        /// </example>
        public static TResult PostData<TPostData, TResult>(string url, TPostData data) where TPostData : class
        {

            var streamReader = new System.IO.StreamReader(new System.IO.MemoryStream());

            var serializer = new DataContractJsonSerializer(typeof(TPostData));
            serializer.WriteObject(streamReader.BaseStream, data);
            streamReader.BaseStream.Position = 0;

            var request = GetRequest(url, "POST");
            request.ContentType = "application/json; charset=utf-8";
            var bytes = System.Text.Encoding.UTF8.GetBytes(streamReader.ReadToEnd());
            request.ContentLength = bytes.Length;

            using (System.IO.Stream stream = request.GetRequestStream())
            {
                stream.Write(bytes, 0, bytes.Length);
                using (System.IO.Stream responseStream = request.GetResponse().GetResponseStream())
                {
                    var desSerializer = new DataContractJsonSerializer(typeof(TResult));
                    ////System.IO.StreamReader r = new System.IO.StreamReader(responseStream);
                    ////string text= r.ReadToEnd();

                    var result = (TResult)desSerializer.ReadObject(responseStream);
                    return result;
                }

            }

        }

        public static object PostData<TPostData>(string url, TPostData data, Type returnType) where TPostData : class
        {

            var streamReader = new System.IO.StreamReader(new System.IO.MemoryStream());

            var serializer = new DataContractJsonSerializer(typeof(TPostData));
            serializer.WriteObject(streamReader.BaseStream, data);
            streamReader.BaseStream.Position = 0;

            var request = GetRequest(url, "POST");
            request.ContentType = "application/json; charset=utf-8";
            var bytes = System.Text.Encoding.UTF8.GetBytes(streamReader.ReadToEnd());
            request.ContentLength = bytes.Length;

            using (System.IO.Stream stream = request.GetRequestStream())
            {
                stream.Write(bytes, 0, bytes.Length);
                using (System.IO.Stream responseStream = request.GetResponse().GetResponseStream())
                {
                    var desSerializer = new DataContractJsonSerializer(returnType);
                    ////System.IO.StreamReader r = new System.IO.StreamReader(responseStream);
                    ////string text= r.ReadToEnd();

                    var result = desSerializer.ReadObject(responseStream);
                    return result;
                }

            }

        }

        private static System.Net.WebRequest GetRequest(string url, string method)
        {
            if (url == null || url.Trim().Length == 0)
                throw new ArgumentNullException("服务地址为空，参数：url");

            var request = System.Net.WebRequest.Create(url);
            if (method != null && method.Trim().Length > 0)
                request.Method = method;

            return request;
        }
    }
}
